<?php


// 公共函数文件
use app\common\service\promotion\PromotionUserTokenService;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Cell\DataType;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\Border;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use think\facade\Config;
use think\facade\Request;
use app\common\service\utils\RetCodeUtils;
use app\common\service\system\SettingService as SystemSetting;
use app\common\service\system\UserTokenService;
use app\common\service\member\SettingService as MemberSetting;
use app\common\service\member\TokenService as MemberTokenService;
use app\common\service\merchant\MerchantUserTokenService;
use think\Response;

/**
 * 成功返回
 *
 * @param array  $data 数据
 * @param string $msg  提示
 * @param int    $code 返回码
 * 
 * @return json
 */
function success($data = [], $msg = RetCodeUtils::SUCCESS_MSG, $code = RetCodeUtils::SUCCESS)
{
    $res['code'] = $code;
    $res['msg']  = $msg;
    $res['data'] = $data;

    return json($res);
}

/**
 * 错误返回
 * 
 * @param array  $data 数据
 * @param string $msg  提示
 * @param int    $code 返回码
 * 
 * @return json
 */
function error($msg = RetCodeUtils::ERROR_MSG, $data = [], $code = RetCodeUtils::ERROR)
{
    $res['code'] = $code;
    $res['msg']  = $msg;
    $res['data'] = $data;

    return json($res);
}

/**
 * 错误返回（调试使用）
 *
 * @param array  $data 数据
 * @param string $msg  提示
 * @param int    $code 返回码
 * 
 * @return json
 */
function error_e($data = [], $msg = RetCodeUtils::ERROR_MSG, $code = RetCodeUtils::ERROR)
{
    $res['code'] = $code;
    $res['msg']  = $msg;
    $res['time'] = time();
    $res['data'] = $data;

    print_r(json_encode($res, JSON_UNESCAPED_UNICODE));

    exit;
}

/**
 * 错误返回（抛出异常）
 *
 * @param string $msg  提示
 * @param int    $code 返回码
 * 
 * @return Exception
 */
function exception($msg = RetCodeUtils::ERROR_MSG, $code = RetCodeUtils::ERROR)
{
    throw new \think\Exception($msg, $code);
}

/**
 * 服务器地址
 * 协议和域名
 *
 * @return string
 */
function server_url()
{
    return Request::domain();
}

/**
 * 文件地址
 * 协议/域名/文件路径
 *
 * @param string $file_path 文件路径
 * 
 * @return string
 */
function file_url($file_path = '')
{
    if (empty($file_path)) {
        return '';
    }

    if (strpos($file_path, 'http') !== false) {
        return $file_path;
    }

    $server_url = server_url();

    if (stripos($file_path, '/') === 0) {
        $file_url = $server_url . $file_path;
    } else {
        $file_url = $server_url . '/' . $file_path;
    }

    return $file_url;
}

/**
 * 文件ids
 *
 * @param array  $files 文件列表 eg: [['file_id'=>1]]
 * @param string $field 文件id字段
 * 
 * @return array eg：[1,2,3]
 */
function file_ids($files = [], $field = 'file_id')
{
    foreach ($files as $val) {
        if ($val[$field] ?? 0) {
            $file_ids[] = $val[$field];
        }
    }
    return $file_ids ?? [];
}

/**
 * http get 请求
 *
 * @param string $url    请求地址
 * @param array  $header 请求头部
 *
 * @return array
 */
function http_get($url, $header = [])
{
    $header = array_merge($header, ['Content-type:application/json', 'Accept:application/json']);

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    $response = curl_exec($curl);
    curl_close($curl);
    $response = json_decode($response, true);

    return $response;
}

/**
 * http post 请求
 *
 * @param string $url    请求地址
 * @param array  $param  请求参数
 * @param array  $header 请求头部
 *
 * @return array
 */
function http_post($url, $param = [], $header = [])
{
    $param = json_encode($param);

    $header = array_merge($header, ['Content-type:application/json;charset=utf-8', 'Accept:application/json']);

    $curl = curl_init();
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
    curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
    curl_setopt($curl, CURLOPT_POST, 1);
    curl_setopt($curl, CURLOPT_POSTFIELDS, $param);
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
    $response = curl_exec($curl);
    curl_close($curl);
    $response = json_decode($response, true);

    return $response;
}

/**
 * 获取当前日期时间
 * 
 * @param string $format 格式，默认Y-m-d H:i:s
 *
 * @return string
 */
function datetime($format = 'Y-m-d H:i:s')
{
    return date($format);
}

/**
 * 列表转树形
 *
 * @param array   $list  列表数组
 * @param string  $pk    主键名称
 * @param string  $pid   父键名称
 * @param int     $root  根节点id
 * @param string  $child 子节点名称
 *
 * @return array
 */
function list_to_tree($list = [], $pk = 'id', $pid = 'pid', $root = 0,  $child = 'children')
{
    $tree  = [];
    $refer = [];
    foreach ($list as $k => $v) {
        $refer[$v[$pk]] = &$list[$k];
    }
    foreach ($list as $key => $val) {
        $parent_id = 0;
        if (isset($val[$pid])) {
            $parent_id = $val[$pid];
        }
        if ($root == $parent_id) {
            $tree[] = &$list[$key];
        } else {
            if (isset($refer[$parent_id])) {
                $parent = &$refer[$parent_id];
                $parent[$child][] = &$list[$key];
            }
        }
    }
    return $tree;
}

/**
 * 列表转树形（根节点未知）
 *
 * @param array   $list  列表数组
 * @param string  $pk    主键名称
 * @param string  $pid   父键名称
 * @param int     $root  根节点id
 * @param string  $child 子节点名称
 *
 * @return array
 */
function array_to_tree($list = [], $pk = 'id', $pid = 'pid', $child = 'children')
{
    $parent_ids = [];
    foreach ($list as $val) {
        $pids = children_parent_ids($list, $val[$pk], $pk, $pid);
        $parent_ids[] = end($pids);
    }
    $parent_ids = array_unique($parent_ids);
    foreach ($list as &$v) {
        foreach ($parent_ids as $vp) {
            if ($v[$pk] == $vp) {
                $v[$pid] = 0;
            }
        }
    }
    return list_to_tree($list, $pk, $pid, 0, $child);
}

/**
 * 树形转列表
 *
 * @param array  $tree  树形数组
 * @param string $child 子节点名称
 *
 * @return array
 */
function tree_to_list($tree = [], $child = 'children')
{
    $list = [];
    foreach ($tree as $val) {
        if (isset($val[$child])) {
            $children = $val[$child];
            unset($val[$child]);
            $list[] = $val;
            if (is_array($children)) {
                $list = array_merge($list, tree_to_list($children, $child));
            }
        } else {
            $list[] = $val;
        }
    }
    return $list;
}

/**
 * 变量类型转换为数组类型
 *
 * @param mixed $var 要转换的变量
 *
 * @return array
 */
function var_to_array($var)
{
    if (empty($var)) {
        return [];
    }

    if (is_string($var)) {
        if (strpos(',', $var) !== false) {
            $var = explode(',', $var);
        }
    }

    settype($var, 'array');

    return $var;
}

/**
 * 变量是否存在（||）
 *
 * @param array $alls 所有的参数变量
 * @param array $vars 需要检查的变量
 *
 * @return bool
 */
function var_isset($alls, $vars = [])
{
    if (is_string($vars)) {
        $vars = explode(',', $vars);
    }
    foreach ($vars as $var) {
        if (isset($alls[$var])) {
            return true;
        }
    }
    return false;
}

/**
 * 用户token
 *
 * @return string
 */
function user_token()
{
    $system = Config::get('admin');
    if ($system['token_type'] == 'header') {
        $user_token = Request::header($system['token_name'], '');
    } else {
        $user_token = Request::param($system['token_name'], '');
    }

    if (empty($user_token)) {
        $user_token = Request::param($system['token_name'], '');
        if (empty($user_token)) {
            $user_token = Request::header($system['token_name'], '');
        }
    }

    return $user_token;
}

/**
 * 用户token验证
 *
 * @param string $user_token 用户token
 *
 * @return Exception
 */
function user_token_verify($user_token = '')
{
    if (empty($user_token)) {
        $user_token = user_token();
    }

    UserTokenService::verify($user_token);
}

/**
 * 用户id
 * 
 * @param bool $exce 未登录是否抛出异常
 *
 * @return int
 */
function user_id($exce = false)
{
    $user_token = user_token();

    return UserTokenService::userId($user_token, $exce);
}

/**
 * 系统超管用户id（所有权限）
 *
 * @return array
 */
function user_super_ids()
{
    return Config::get('admin.super_ids', []);
}

/**
 * 用户是否系统超管
 *
 * @param int $user_id 用户id
 * 
 * @return bool
 */
function user_is_super($user_id = 0)
{
    if (empty($user_id)) {
        return false;
    }

    $user_super_ids = user_super_ids();
    if (empty($user_super_ids)) {
        return false;
    }
    if (in_array($user_id, $user_super_ids)) {
        return true;
    } else {
        return false;
    }
}

/**
 * 系统超管用户上传文件大小是否不受限制
 *
 * @return bool
 */
function super_upload_size()
{
    if (user_is_super(user_id())) {
        return Config::get('admin.super_upload_size', false);
    }
    return false;
}

/**
 * 用户日志记录是否开启
 *
 * @return bool
 */
function user_log_switch()
{
    $system = SystemSetting::info();
    if ($system['log_switch']) {
        return true;
    } else {
        return false;
    }
}

/**
 * 系统超管用户记录隐藏条件
 * 
 * @param string $user_id_field 用户id字段
 *
 * @return array
 */
function user_hide_where($user_id_field = 'user_id')
{
    $super_hide = Config::get('admin.super_hide', false);
    if ($super_hide) {
        $user_id = user_id();
        if (!user_is_super($user_id)) {
            $user_super_ids = user_super_ids();
            if ($user_super_ids) {
                $where = [$user_id_field, 'not in', $user_super_ids];
            }
        }
    }
    return $where ?? [];
}

/**
 * 接口token获取
 *
 * @return string
 */
function api_token()
{
    $setting = Config::get('api');
    if ($setting['token_type'] == 'header') {
        $api_token = Request::header($setting['token_name'], '');
    } else {
        $api_token = Request::param($setting['token_name'], '');
    }

    if (empty($api_token)) {
        $api_token = Request::param($setting['token_name'], '');
        if (empty($api_token)) {
            $api_token = Request::header($setting['token_name'], '');
        }
    }

    return $api_token;
}

/**
 * 接口token验证
 *
 * @param string $api_token 接口token
 *
 * @return Exception
 */
function api_token_verify($api_token = '')
{
    if (empty($api_token)) {
        $api_token = api_token();
    }

    MemberTokenService::verify($api_token);
}

/**
 * 会员id获取
 * 
 * @param bool $exce 未登录是否抛出异常
 *
 * @return int
 */
function member_id($exce = false)
{
    $api_token = api_token();

    return MemberTokenService::memberId($api_token, $exce);
}

/**
 * 会员平台获取
 * 
 * @param bool $exce 未登录是否抛出异常
 *
 * @return int
 */
function member_platform($exce = false)
{
    $api_token = api_token();

    return MemberTokenService::memberPlatform($api_token, $exce);
}

/**
 * 会员应用获取
 * 
 * @param bool $exce 未登录是否抛出异常
 *
 * @return int
 */
function member_application($exce = false)
{
    $api_token = api_token();

    return MemberTokenService::memberApplication($api_token, $exce);
}

/**
 * 会员日志记录是否开启
 *
 * @return bool
 */
function member_log_switch()
{
    $setting = MemberSetting::info();
    if ($setting['log_switch']) {
        return true;
    } else {
        return false;
    }
}

/**
 * 会员超级会员id（所有权限）
 *
 * @return array
 */
function member_super_ids()
{
    return Config::get('api.super_ids', []);
}

/**
 * 会员是否超级会员
 *
 * @param int $member_id 会员id
 * 
 * @return bool
 */
function member_is_super($member_id = 0)
{
    if (empty($member_id)) {
        return false;
    }

    $member_super_ids = member_super_ids();
    if (empty($member_super_ids)) {
        return false;
    }
    if (in_array($member_id, $member_super_ids)) {
        return true;
    } else {
        return false;
    }
}

/**
 * 获取父级的所有子级id
 *
 * @param array  $list 列表
 * @param int    $id   id
 * @param string $pk   主键
 * @param string $pid  父键
 *
 * @return array id数组
 */
function parent_children_ids($list, $id, $pk = 'id', $pid = 'pid')
{
    $children = [];
    foreach ($list as $v) {
        if ($v[$pid] == $id) {
            $children[] = $v[$pk];
            $children = array_merge($children, parent_children_ids($list, $v[$pk], $pk, $pid));
        }
    }
    return $children;
}

/**
 * 获取子级的所有父级id
 *
 * @param array  $list 列表
 * @param int    $id   id
 * @param string $pk   主键
 * @param string $pid  父键
 *
 * @return array id数组
 */
function children_parent_ids($list, $id, $pk = 'id', $pid = 'pid')
{
    $parentid = [];
    foreach ($list as $v) {
        if ($v[$pk] == $id) {
            $parentid[] = $v[$pk];
            $parentid = array_merge($parentid, children_parent_ids($list, $v[$pid], $pk, $pid));
        }
    }
    return $parentid;
}

/**
 * 获取模型关联字段
 *
 * @param Relation $relation 模型关联结果
 * @param string   $field    需要获取的字段
 * @param bool     $string   是否返回字符串
 * @param bool     $delete   是否筛选已删除
 * @param bool     $disable  是否筛选已禁用
 *
 * @return string|array
 */
function relation_fields($relation, $field, $string = false, $delete = true, $disable = true)
{
    $names = [];
    $array = $relation ?? [];
    if ($array) {
        $array = is_array($array) ? $array : $array->toArray();
        foreach ($array as $key => $val) {
            if ($delete && $val['is_delete']) {
                unset($array[$key]);
            }
            if ($disable && $val['is_disable']) {
                unset($array[$key]);
            }
        }
    }
    if (empty($field)) {
        return $array;
    }
    $names = array_column($array, $field);
    if ($string) {
        return implode(',', $names);
    }
    return $names;
}

/**
 * 模型关联修改
 * 
 * @param Model  $info     模型find查询
 * @param array  $old_ids  旧的关联id
 * @param array  $new_ids  新的关联id
 * @param string $relation 关联方法名
 * @param array  $pivot    额外属性
 * 
 * @return void
 */
function relation_update($info, $old_ids, $new_ids, $relation, $pivot = [])
{
    if ($new_ids) {
        $new_diff = array_diff_assoc($old_ids, $new_ids);
        $old_diff = array_diff_assoc($new_ids, $old_ids);
        if ($new_diff || $old_diff) {
            $info->$relation()->detach($old_ids);
            $info->$relation()->attach($new_ids, $pivot);
        }
    } else {
        $info->$relation()->detach($old_ids);
    }
}

/**
 * 查询条件是否禁用
 *
 * @param array $where   其它条件
 * @param int   $disable 0未禁用，1已禁用
 *
 * @return array
 */
function where_disable($where = [], $disable = 0)
{
    $where_other = [];
    $where_disable = ['is_disable', '=', $disable];
    if ($where) {
        foreach ($where as $value) {
            if (is_array($value)) {
                $where_other[] = $value;
            } else {
                $where_other[] = $where;
                break;
            }
        }
        $where_other[] = $where_disable;
        return $where_other;
    }
    return $where_disable;
}

/**
 * 查询条件是否删除
 *
 * @param array $where  其它条件
 * @param int   $delete 0未删除，1已删除
 *
 * @return array
 */
function where_delete($where = [], $delete = 0)
{
    $where_other = [];
    $where_delete = ['is_delete', '=', $delete];
    if ($where) {
        foreach ($where as $value) {
            if (is_array($value)) {
                $where_other[] = $value;
            } else {
                $where_other[] = $where;
                break;
            }
        }
        $where_other[] = $where_delete;
        return $where_other;
    }
    return $where_delete;
}

/**
 * 查询条件是否禁用、删除
 *
 * @param array $where   其它条件
 * @param int   $disable 0未禁用，1已禁用
 * @param int   $delete  0未删除，1已删除
 *
 * @return array
 */
function where_disdel($where = [], $disable = 0, $delete = 0)
{
    $where_other = [];
    $where_disdel = [['is_disable', '=', $disable], ['is_delete', '=', $delete]];
    if ($where) {
        foreach ($where as $value) {
            if (is_array($value)) {
                $where_other[] = $value;
            } else {
                $where_other[] = $where;
                break;
            }
        }
        $where_other[] = $where_disdel[0];
        $where_other[] = $where_disdel[1];
        return $where_other;
    }
    return $where_disdel;
}

/**
 * 查询表达式
 *
 * @param string $exp 需要返回的表达式，eg：=,>
 *
 * @return array [['exp'=>'=','name'=>'包含']...]
 */
function where_exps($exp = '')
{
    $exps = [
        ['exp' => 'like', 'name' => '包含'],
        ['exp' => 'not like', 'name' => '不包含'],
        ['exp' => '=', 'name' => '等于'],
        ['exp' => '<>', 'name' => '不等于'],
        ['exp' => '>', 'name' => '大于'],
        ['exp' => '>=', 'name' => '大于等于'],
        ['exp' => '<', 'name' => '小于'],
        ['exp' => '<=', 'name' => '小于等于'],
        ['exp' => 'between', 'name' => '在区间'],
        ['exp' => 'not between', 'name' => '不在区间'],
        ['exp' => 'in', 'name' => '在列表'],
        ['exp' => 'not in', 'name' => '不在列表'],
    ];

    if ($exp) {
        $exp = explode(',', $exp);
        foreach ($exps as $val) {
            foreach ($exp as $v) {
                if ($val['exp'] == $v) {
                    $tmp[] = $val;
                }
            }
        }
        return $tmp ?? [];
    }

    return $exps;
}

/**
 * 查询条件字段缓存键名
 *
 * @param  string $type  类型
 * @param  array  $where 条件
 * @param  array  $order 排序
 * @param  string $field 字段
 * @param  string $sort  asc升序，desc降序
 *
 * @return string
 */
function where_cache_key($type, $where, $order, $field, $sort = 'asc')
{
    $field = explode(',', $field);

    if ($sort == 'asc') {
        sort($where);
        sort($order);
        sort($field);
    } else {
        rsort($where);
        rsort($order);
        rsort($field);
    }

    return $type . md5(serialize($where) . serialize($order) . serialize($field));
}

/**
 * 软删除更新数据
 *
 * @param array  $data  其它数据
 * @param string $field 排除字段
 *
 * @return array
 */
function delete_update($data = [], $field = '')
{
    $data['is_delete']   = 1;
    $data['delete_uid']  = user_id();
    $data['delete_time'] = datetime();

    if ($field) {
        $fields = explode(',', $field);
        foreach ($fields as $field) {
            unset($data[$field]);
        }
    }

    return $data;
}
function mer_delete_update($data = [], $field = '')
{
    $data['is_delete']   = 1;
    $data['delete_uid']  = mer_id();
    $data['delete_time'] = datetime();

    if ($field) {
        $fields = explode(',', $field);
        foreach ($fields as $field) {
            unset($data[$field]);
        }
    }

    return $data;
}
function promotion_delete_update($data = [], $field = '')
{
    $data['is_delete']   = 1;
    $data['delete_uid']  = promotion_id();
    $data['delete_time'] = datetime();

    if ($field) {
        $fields = explode(',', $field);
        foreach ($fields as $field) {
            unset($data[$field]);
        }
    }

    return $data;
}
/**
 * 生成state
 *
 * @param  string $prefix       前缀
 * @param  bool   $more_entropy 是否增加额外的熵
 *
 * @return string
 */
function create_state($prefix = '', $more_entropy = true)
{
    return md5(uniqid($prefix, $more_entropy));
}

/**
 * 商家用户id
 *
 * @param bool $exce 未登录是否抛出异常
 *
 * @return int
 */
function mer_user_id($exce = false)
{
    $user_token = mer_user_token();

    return MerchantUserTokenService::merUserId($user_token, $exce);
}
/**
 * 商家id
 *
 * @param bool $exce 未登录是否抛出异常
 *
 * @return int
 */
function mer_id($exce = false)
{
    $user_token = mer_user_token();

    return MerchantUserTokenService::merId($user_token, $exce);
}
/**
 * 用户token
 *
 * @return string
 */
function mer_user_token()
{
    $system = Config::get('merchant');
    if ($system['token_type'] == 'header') {
        $user_token = Request::header($system['token_name'], '');
    } else {
        $user_token = Request::param($system['token_name'], '');
    }
    if (empty($user_token)) {
        $user_token = Request::param($system['token_name'], '');
        if (empty($user_token)) {
            $user_token = Request::header($system['token_name'], '');
        }
    }

    return $user_token;
}

/**
 * 商家超管用户记录隐藏条件
 *
 * @param string $user_id_field 用户id字段
 *
 * @return array
 */
function mer_user_hide_where($user_id_field = 'mer_user_id')
{
    $super_hide = Config::get('merchant.super_hide', false);
    if ($super_hide) {
        $user_id = mer_user_id();
        if (!mer_user_is_super($user_id)) {
            $user_super_ids = mer_user_super_ids();
            if ($user_super_ids) {
                $where = [$user_id_field, 'not in', $user_super_ids];
            }
        }
    }
    return $where ?? [];
}
/**
 * 商家用户是否系统超管
 *
 * @param int $user_id 用户id
 *
 * @return bool
 */
function mer_user_is_super($user_id = 0)
{
    if (empty($user_id)) {
        return false;
    }

    $user_super_ids = mer_user_super_ids();
    if (empty($user_super_ids)) {
        return false;
    }
    if (in_array($user_id, $user_super_ids)) {
        return true;
    } else {
        return false;
    }
}

/**
 * 商家超管用户id（所有权限）
 *
 * @return array
 */
function mer_user_super_ids()
{
    return Config::get('merchant.super_ids', []);
}

/**
 * 商家用户token验证
 *
 * @param string $user_token 用户token
 *
 * @return Exception
 */
function mer_user_token_verify($user_token = '')
{
    if (empty($user_token)) {
        $user_token = mer_user_token();
    }

    MerchantUserTokenService::verify($user_token);
}

/**
 * 计算开始时间与结束时间相差多少分钟
 * @Author: 易军辉
 * @DateTime:2024-06-05 18:11
 * @param $start_time
 * @param $end_time
 * @return float|int
 * @throws Exception
 */
function minuteCalculation($start_time, $end_time)
{
    // 设置开始时间和结束时间
    $start_time = new DateTime($start_time);
    $end_time = new DateTime($end_time);

    // 计算时间间隔
    $interval = $start_time->diff($end_time);

    // 将时间间隔转换为分钟
    $total_minutes = $interval->days * 24 * 60 + $interval->h * 60 + $interval->i;
    return $total_minutes;
}

/**
 * 计算开始时间与结束时间相差多少小时
 * @Author: 易军辉
 * @DateTime:2024-09-13 20:54
 * @param $start_time
 * @param $end_time
 */
function hourCalculation($start_time, $end_time)
{
    // 设置开始时间和结束时间
    $start_time = new DateTime($start_time);
    $end_time = new DateTime($end_time);

    // 计算时间间隔
    $interval = $start_time->diff($end_time);

    // 将时间间隔转换为分钟
    $total_hours = $interval->days * 24 + $interval->h + $interval->i / 60;
    return $total_hours;
}
/**
 * @param string $title 导出名称
 * @param array $head 标题[['标题'],['第二行第一个','第二行第二个']]
 * @param array $list 数据
 * @param array $list_field 那一列用那个字段,示例['id','name','age']
 * @param array $merge 合并,示例['A1:C1','A2:F2']
 * @param array $styles 样式,示例['A1'=>[...],'B2:F2'=>[...]]
 * @param array $decimals 保留两位小数的字段,与$list_field类似：['age']
 * @param boolean $isTotal 是否合计
 * @param array $text_field 那些字段需要转为文本,示例['id','name','age']
 */
function excelExport($title = "", $head = [], $list = [], $list_field = [], $merge = [], $styles = [], $decimals = [], $isTotal = true, $text_field = [])
{
    try {
        // 实例化Spreadsheet对象
        $spreadsheet = new Spreadsheet();
        $sheetMain = $spreadsheet->getsheet(0); // 设置主sheet
        $sheetMain->setTitle($title); // 设置sheet的名称
        $sheetMain->getPageSetup()->setHorizontalCentered(true);
        $sheetMain->getPageSetup()->setVerticalCentered(false);
        //合并
        foreach ($merge as $key => $val) {
            $sheetMain->mergeCells($val);
        }
        //设置头部标题
        $rowNum = 1;//行数
        $maxRank = 0;//最大列
        $widths = [];
        foreach ($head as $key => $val) {//第几行
            foreach ($val as $k => $v) {//第几列
                if ($maxRank < $k) {
                    $maxRank = $k;
                }

                $y = Coordinate::stringFromColumnIndex(bcadd($k, 1, 0));//根据列计算 列名  A B C D
                $sheetMain->setCellValue($y . $rowNum, $v);
                //设置标题样式
                $styleArray = [                        'font' => ['bold' => true, 'size' => 18],
                    'alignment' => ['horizontal' => Alignment::HORIZONTAL_CENTER],
                ];
                $sheetMain->getStyle($y . $rowNum)->applyFromArray($styleArray);
                //获取每列最大宽度,当有两行标题，第一行标题不计算宽度
                if (count($head) >= 2 && $k == 0 && count($list) > 0) {
                    continue;
                }

                if (isset($widths[$k]) && $widths[$k] < (strlen(iconv('utf-8', 'GB2312//IGNORE', $v)) + 6)) {
                    $widths[$k] = strlen(iconv('utf-8', 'GB2312//IGNORE', $v)) + 6;
                } else if (!isset($widths[$k])) {
                    $widths[$k] = strlen(iconv('utf-8', 'GB2312//IGNORE', $v)) + 6;
                }
            }
            $rowNum++;
        }
        $decimals_key = [];//合计对应的列
        $options = "//TRANSLIT"; //字段值为：增值税 – 附加税 导出报错 iconv(): Detected an illegal character in input string，解决办法
        //设置数据
        foreach ($list as $key => $val) {
            if (count($list_field) > 0) {
                foreach ($list_field as $k => $v) {
                    if (isset($val[$v])) {
                        if ($maxRank < $k) {
                            $maxRank = $k;
                        }
                        //获取每列最大宽度
                        if (isset($widths[$k]) && $widths[$k] < (strlen(iconv('utf-8', 'GB2312//IGNORE', $val[$v])) + 8)) {
                            $widths[$k] = strlen(iconv('utf-8', 'GB2312//IGNORE', $val[$v])) + 8;
                        } else if (!isset($widths[$k])) {
                            $widths[$k] = strlen(iconv('utf-8', 'GB2312//IGNORE', $val[$v])) + 8;
                        }
                        $y = Coordinate::stringFromColumnIndex(bcadd($k, 1, 0));//根据列计算 列名  A B C D
                        //设置文本
                        if (in_array($v, $text_field)) {
                            $sheetMain->getStyle($y . $rowNum)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_TEXT);
                            $sheetMain->setCellValueExplicit($y . $rowNum, $val[$v], DataType::TYPE_STRING);
                        } else {
                            $sheetMain->setCellValue($y . $rowNum, $val[$v]);
                        }

                        //设置两位小数
                        if (in_array($v, $decimals)) {
                            $sheetMain->getStyle($y . $rowNum)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1);
                            $decimals_key[$v] = $k;
                        }

                    }
                }
            } else {
                if ($maxRank < $key) {
                    $maxRank = $key;
                }
                //获取每列最大宽度
                if (isset($widths[$key]) && $widths[$key] < (strlen(iconv('utf-8', 'GB2312//IGNORE', $val)) + 8)) {
                    $widths[$key] = strlen(iconv('utf-8', 'GB2312//IGNORE', $val)) + 8;
                } else if (!isset($widths[$key])) {
                    $widths[$key] = strlen(iconv('utf-8', 'GB2312//IGNORE', $val)) + 8;
                }
                //当一维数组处理
                $y = Coordinate::stringFromColumnIndex(bcadd($key, 1, 0));//根据列计算 列名  A B C D
                $sheetMain->setCellValue($y . $rowNum, $val);
            }
            $rowNum++;
        }

        if (count($decimals) <= 0 || !$isTotal) {
            $rowNum -= 1;
        } else {
            //设置合计列
            $is_one = false;//A列是否有合计数据
            foreach ($decimals_key as $key => $val) {
                if ($val == 0) {
                    $is_one = true;
                }
                $y = Coordinate::stringFromColumnIndex(bcadd($val, 1, 0));//根据列计算 列名  A B C D
                $sheetMain->setCellValue($y . $rowNum, '=sum(' . $y . (count($head) + 1) . ':' . $y . ($rowNum - 1) . ')');
                $sheetMain->getStyle($y . $rowNum)->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_NUMBER_COMMA_SEPARATED1);
            }
            if (!$is_one && count($decimals_key) > 0) {
                $sheetMain->setCellValue('A' . $rowNum, 'TOTAL：');
                $sheetMain->getStyle('A' . $rowNum)->applyFromArray(['alignment' => ['horizontal' => Alignment::HORIZONTAL_RIGHT]]);
            }
        }
        //设置公共样式
        $maxRankStr = Coordinate::stringFromColumnIndex(bcadd($maxRank, 1, 0));
        $sheetMain->getStyle('A1:' . $maxRankStr . $rowNum)->getAlignment()->setWrapText(true)->setVertical(Alignment::VERTICAL_CENTER);//自动换行+垂直居中
        $sheetMain->getStyle('A2:' . $maxRankStr . $rowNum)->getFont()->setName('SimSun')->setSize(11);
        //设置边框
        $borderStyle = array(
            'borders' => array(
                'allBorders' => [                        'borderStyle' => Border::BORDER_THIN
                ]
            ),
        );
        $sheetMain->getStyle('A1:' . $maxRankStr . $rowNum)->applyFromArray($borderStyle);
        // 设置要自动调整宽度的行
        foreach ($widths as $key => $val) {
            $y = Coordinate::stringFromColumnIndex(bcadd($key, 1, 0));//根据列计算 列名  A B C D
            $sheetMain->getColumnDimension($y)->setWidth($val);
        }
        //设置行高
        for ($i = 1; $i <= $rowNum; $i++) {
            //只有一行标题
            if (count($head) == 1 && $i == 1) {
                $sheetMain->getRowDimension($i)->setRowHeight(30);
            } else if (count($head) >= 2) {
                if ($i == 1) {
                    $sheetMain->getRowDimension($i)->setRowHeight(30);
                } else if ($i <= count($head)) {
                    $sheetMain->getRowDimension($i)->setRowHeight(25);
                } else {
                    $sheetMain->getRowDimension($i)->setRowHeight(20);
                }
            } else {
                $sheetMain->getRowDimension($i)->setRowHeight(20);
            }
        }
        //设置样式
        foreach ($styles as $key => $val) {
            $sheetMain->getStyle($key)->applyFromArray($val);
        }

        //定义文件名称，需要带有定义的后缀名
        $filename = $title . '.xlsx';
        ob_end_clean(); //清除缓冲区,避免乱码
        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
        // 创建临时文件并将数据写入其中
        $tempFile = tempnam(sys_get_temp_dir(), 'excel_');
        $writer->save($tempFile);

        // 构建响应对象
        $response = Response::create(file_get_contents($tempFile), 'html', 200)
            ->contentType('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
            ->header([
                'Content-Disposition' => 'attachment; filename="' . urlencode($filename) . '"',
                'Cache-Control' => 'max-age=0;filename="' . urlencode($filename)  . '"'
            ]);

        // 删除临时文件
        unlink($tempFile);

        return $response;
    } catch (\Exception $e) {
        throw new Exception($e->getMessage());
    }
}


/**
 * 推广用户id
 *
 * @param bool $exce 未登录是否抛出异常
 *
 * @return int
 */
function promotion_user_id($exce = false)
{
    $user_token = promotion_user_token();

    return PromotionUserTokenService::userId($user_token, $exce);
}
/**
 * 用户token
 *
 * @return string
 */
function promotion_user_token()
{
    $system = Config::get('promotion');
    if ($system['token_type'] == 'header') {
        $user_token = Request::header($system['token_name'], '');
    } else {
        $user_token = Request::param($system['token_name'], '');
    }
    if (empty($user_token)) {
        $user_token = Request::param($system['token_name'], '');
        if (empty($user_token)) {
            $user_token = Request::header($system['token_name'], '');
        }
    }

    return $user_token;
}

/**
 * 推广员记录隐藏条件
 *
 * @param string $user_id_field 用户id字段
 *
 * @return array
 */
function promotion_user_hide_where($user_id_field = 'promotion_user_id')
{
    $super_hide = Config::get('promotion.super_hide', false);
    if ($super_hide) {
        $user_id = promotion_user_id();
        if (!promotion_user_is_super($user_id)) {
            $user_super_ids = promotion_user_super_ids();
            if ($user_super_ids) {
                $where = [$user_id_field, 'not in', $user_super_ids];
            }
        }
    }
    return $where ?? [];
}
/**
 * 推广员是否系统超管
 *
 * @param int $user_id 用户id
 *
 * @return bool
 */
function promotion_user_is_super($user_id = 0)
{
    if (empty($user_id)) {
        return false;
    }

    $user_super_ids = promotion_user_super_ids();
    if (empty($user_super_ids)) {
        return false;
    }
    if (in_array($user_id, $user_super_ids)) {
        return true;
    } else {
        return false;
    }
}

/**
 * 推广员超管用户id（所有权限）
 *
 * @return array
 */
function promotion_user_super_ids()
{
    return Config::get('promotion.super_ids', []);
}

/**
 * 推广员token验证
 *
 * @param string $user_token 用户token
 *
 * @return Exception
 */
function promotion_user_token_verify($user_token = '')
{
    if (empty($user_token)) {
        $user_token = promotion_user_token();
    }

    PromotionUserTokenService::verify($user_token);
}

/**
 * 操作用户
 * @Author: 易军辉
 * @DateTime:2024-09-25 16:58
 * @return int
 */
function operate_user_id()
{
    $user_id = user_id();
    if($user_id<=0){
        $user_id = mer_user_id();
    }
    if($user_id<=0){
        $user_id = member_id();
    }
    return $user_id;
}